package han.chensing.latos.maker.windows.widget.line;

/**
 * 20240409 考试给我输惨了...先不提这个，这个类将会迎来一次重构
 * Refactor it, add some interesting things
 * Such as ... something like simulator..?
 *
 * FIXME 20240928 这个类将被直接弃用，然后实现新的解决方案，目前仅供参考，将在之后删除！
 */
/*@SuppressWarnings("ALL")
@Deprecated
public class OldLineEditorWidget extends Widget {

    private static final HashMap<Integer,Color> colorMap;
    static {
        colorMap=new HashMap<>();
        colorMap.put(2,new Color(0x001EFFFF));
        colorMap.put(4,new Color(0x768CCFFF));
        colorMap.put(8,new Color(0x78D8E4FF));
        colorMap.put(16,new Color(0x5DE4B0FF));
        colorMap.put(32,new Color(0xE48036FF));
        colorMap.put(3,new Color(0xFF002FFF));
        colorMap.put(6,new Color(0xFF2EB4FF));
        colorMap.put(12,new Color(0xDF97FFFF));
        colorMap.put(24,new Color(0xBFBEFFFF));
        colorMap.put(1,new Color(0xFFFFFFFF));
        colorMap.put(-1,new Color(0xEA74DEFF));
    }

    Color backgroundColor=new Color(0x1f1e33ff);
    CommonLine nowCommonLine;
    float nowTime=0;
    float speed=100f;
    int yellowLineOffset = 70;
    int noteWidth=100,noteHeight=8;
    float hScale=1.0f;
    int notePlacing=-1;
    float selectedTime;
    boolean editDialogMode =true;

    List<Object[]> alignmentList;

    boolean isScaling=false;
    float scalingSx,scalingSy, scalingSHScale,scalingSSpeed;
    boolean isDragging=false;
    float draggingSy,draggingStartTime;
    boolean isSelecting=false;
    float selectingSx,selectingSy,selectingX,selectingY;

    List<CommonNote> selectedCommonNote;

    CheckBox enableSoundCheck;

    public OldLineEditorWidget(CheckBox enableSoundCheck){
        this.enableSoundCheck=enableSoundCheck;
        alignmentList=Collections.synchronizedList(new ArrayList<>());
        addListener(new InputListener(){
            @Override
            public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                switch (button){
                    case Input.Buttons.LEFT:{
                        if (notePlacing!=-1){
                            placeNote(x,y);
                            break;
                        }
                        draggingStartTime=nowTime;
                        isDragging=true;
                        draggingSy=y;
                        break;
                    }
                    case Input.Buttons.MIDDLE:{
                        scalingSx=x;
                        scalingSy=y;
                        scalingSHScale=hScale;
                        scalingSSpeed=speed;
                        isScaling=true;
                        break;
                    }
                    case Input.Buttons.RIGHT:{
                        isSelecting=true;
                        selectingSx=selectingX=x;
                        selectingSy=selectingY=y;
                        break;
                    }
                }
                return true;
            }
            @Override
            public void touchDragged(InputEvent event, float x, float y, int pointer) {
                super.touchDragged(event, x, y, pointer);
                if (isScaling){
                    float dx=scalingSx-x;
                    float dy=scalingSy-y;
                    hScale=Math.max(100,scalingSHScale-dx*3f);
                    speed=Math.max(100,scalingSSpeed-dy*3f);
                }
                if (isDragging){
                    float dy = (draggingSy - y)/speed;
                    float length = V.project.getMusicLength();
                    nowTime= MathUtil.range(0,draggingStartTime+dy,length);
                }
                if (isSelecting){
                    selectingX=x;
                    selectingY=y;
                }
            }

            @Override
            public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
                super.touchUp(event, x, y, pointer, button);
                if (isDragging&&editDialogMode) {
                    resetNoteHitSoundStatus();
                    Music music = V.project.getMusic();
                    music.play();
                    music.setPosition((nowTime));
                    music.pause();
                }
                if (isSelecting&& editDialogMode){
                    LevelLineEditorDialog parent = (LevelLineEditorDialog) getParent();
                    updateSelectedNotes();
                    parent.updateSelectedNotes(selectedCommonNote);
                }
                isScaling=false;
                isDragging=false;
                isSelecting=false;
            }
        });
        selectedCommonNote =new ArrayList<>();
    }

    @Override
    public void draw(Batch batch, float parentAlpha) {
        super.draw(batch, parentAlpha);
        if (((BaseDialog) getParent()).isOnBottom())
            return;
        float x = getX();
        float y = getY();
        float width = getWidth();
        float height = getHeight();
        GameMain.shapeDrawer.filledRectangle(x,y,width,height, backgroundColor);
        GameMain.shapeDrawer.line(x,y+ yellowLineOffset,x+width,y+ yellowLineOffset,2,
                Color.YELLOW,Color.YELLOW);
        drawAlignmentLine();
        drawLine();
        if (isSelecting){
            GameMain.shapeDrawer.rectangle(
                    getX()+selectingSx,getY()+selectingSy,
                    selectingX-selectingSx,
                    selectingY-selectingSy,
                    Color.WHITE);
        }
        if (!isDragging&&editDialogMode)
            nowTime= (V.project.getMusic().getPosition());
    }

    public void drawLine(){
        if (nowCommonLine ==null)
            return;
        Sound tapSound = Res.get().get("tapSound", Sound.class);
        Sound dragSound = Res.get().get("dragSound", Sound.class);
        Sound flickSound = Res.get().get("flickSound", Sound.class);
        ArrayList<CommonNote> commonNotes = nowCommonLine.getNotes();
        ShapeDrawer shapeRenderer = GameMain.shapeDrawer;
        shapeRenderer.rectangle(
                getX()+getWidth()/2+getWidth()/2*hScale,getY(),2,getHeight()
                ,Color.WHITE
        );
        shapeRenderer.rectangle(
                getX()+getWidth()/2-getWidth()/2*hScale,getY(),2,getHeight()
                ,Color.WHITE
        );
        Rectangle selectingRect=getSelectedRectangle();
        float offset = V.project.getLatosMetaData().getOffset();
        int[] bottomAndTopNoteIndex = getBottomAndTopNoteIndex(commonNotes);
        int size = commonNotes.size();
        for (int i = bottomAndTopNoteIndex[0];i<size&&i<bottomAndTopNoteIndex[1];i++){
            CommonNote commonNote = commonNotes.get(i);
            float[] notePosition = getNotePosition(commonNote);
            if (notePosition==null)
                continue;
            if (commonNote.getEditorExtraData()[0]!=null&&(boolean) commonNote.getEditorExtraData()[0]
                    && commonNote.getBindSample().getTime()-offset <= nowTime) {
                if (enableSoundCheck.isChecked()) {
                    float distanceToLineCenter = commonNote.getDistanceToLineCenter();
                    float pan = MathUtil.range(-1, distanceToLineCenter / 960f, 1);
                    switch (commonNote.getNoteType()) {
                        case Hold, Tap -> tapSound.play(1, 1, pan);
                        case Drag -> dragSound.play(1, 1, pan);
                        case Flick -> flickSound.play(1, 1, pan);
                    }
                }
                commonNote.getEditorExtraData()[0] = false;
            }
            float x = notePosition[0];
            float y = notePosition[1];
            float width = notePosition[2];
            float height = notePosition[3];
            Color noteColor = CommonNote.getNoteColor(commonNote);
            shapeRenderer.rectangle(
                    x, y, width, height,
                    noteColor);
            if (commonNote.getNoteType()== CommonNote.NoteType.Hold){
                shapeRenderer.setColor(noteColor);
                float[] holdNoteEndPosition = getHoldNoteEndPosition(commonNote);
                if (holdNoteEndPosition!=null)
                    shapeRenderer.rectangle(x,y,width,holdNoteEndPosition[1]-y);
                shapeRenderer.setColor(1,1,1,1);
            }
            if (isSelecting){
                Rectangle rectangle=new Rectangle(x, y, width, height);
                boolean overlaps = selectingRect.overlaps(rectangle);
                if (overlaps){
                    shapeRenderer.rectangle(x -3, y -3, width +6, height +6,
                            Color.WHITE);
                }
            }else {
                if (selectedCommonNote.contains(commonNote)) {
                    shapeRenderer.rectangle(x - 3, y - 3, width + 6, height + 6,
                            Color.WHITE);
                }
            }
        }
    }

    private int[] getBottomAndTopNoteIndex(List<CommonNote> commonNotes){
        float offset = V.project.getLatosMetaData().getOffset();
        float bottomTime = nowTime - yellowLineOffset / speed;
        float topTime = nowTime + (getHeight() - yellowLineOffset) / speed+offset;
        int index=0;
        int bottomIndex=0;
        int topIndex= commonNotes.size();
        boolean foundBottom=false;
        for (CommonNote commonNote : commonNotes) {
            if (commonNote.getBindSample().getTime()>=bottomTime&&!foundBottom) {
                foundBottom=true;
                bottomIndex = index;
            }
            if (commonNote.getBindSample().getTime()>=topTime){
                topIndex=index;
                break;
            }
            index++;
        }
        return new int[]{bottomIndex,topIndex};
    }

    private void drawAlignmentLine(){
        for (Object[] objects : alignmentList) {
            int m = (int) objects[0];
            Color color = (Color) objects[1];
            drawAAlignmentLine(1f/m,color);
        }
    }

    private void drawAAlignmentLine(float beatStep,Color color){
        float bpm = V.project.getLatosMetaData().getDefaultBpm();
        float offset = V.project.getLatosMetaData().getOffset();
        float k = 60f;
        float bottomTime=yellowLineOffset/speed;
        float beat= bpm*(nowTime-bottomTime)/ k;
        float floorBeat= (float) Math.floor(beat);
        float mpb=k/bpm;
        float floorTime=floorBeat*mpb;
        float height = getHeight();
        float fullTime = height / speed+mpb+offset;
        float timeStep = beatStep * mpb;
        float x = getX();
        float width = getWidth();
        for(float i=floorTime;i<floorTime+fullTime;i+=timeStep){
            float[] position = fromTimeToPosition((long)i, 0);
            if (position==null)
                continue;
            float y = position[1]+noteHeight/2f;
            GameMain.shapeDrawer.line(x,y, x + width,y,2,
                    color,color);
        }
    }

    private float[] getNotePosition(CommonNote commonNote){
        float offset = V.project.getLatosMetaData().getOffset();
        Sample bindSample = commonNote.getBindSample();
        if (bindSample == null)
            return null;
        float absTime = bindSample.getTime()-offset;
        float distanceToLineCenter = commonNote.getDistanceToLineCenter();
        return fromTimeToPosition(absTime,distanceToLineCenter);
    }

    private float[] getHoldNoteEndPosition(CommonNote commonNote){
        float offset = V.project.getLatosMetaData().getOffset();
        Sample bindSample = commonNote.getBindEndSample();
        if (bindSample == null)
            return null;
        float absTime = bindSample.getTime()-offset;
        float distanceToLineCenter = commonNote.getDistanceToLineCenter();
        return fromTimeToPosition(absTime,distanceToLineCenter);
    }

    public void updateSelectedNotes(){
        if (nowCommonLine ==null)
            return;
        ArrayList<CommonNote> commonNotes = nowCommonLine.getNotes();
        Rectangle selectedRectangle = getSelectedRectangle();
        selectedCommonNote.clear();
        for (CommonNote commonNote : commonNotes) {
            float[] notePosition = getNotePosition(commonNote);
            if (notePosition==null)
                continue;
            float x = notePosition[0];
            float y = notePosition[1];
            float width = notePosition[2];
            float height = notePosition[3];
            Rectangle rectangle=new Rectangle(x, y, width, height);
            if (rectangle.overlaps(selectedRectangle))
                selectedCommonNote.add(commonNote);
        }
    }

    private float fromWidgetYToTime(float y){
        float trueY = y - yellowLineOffset;
        return nowTime + trueY / speed;
    }
    private float[] fromTimeToPosition(float absTime,float distanceToLineCenter){
        float diffTime = absTime - (nowTime);
        float pos = diffTime * speed + yellowLineOffset;
        if (pos < 0 || pos > getHeight())
            return null;
        float canvasWidth = getWidth();
        float halfWidth = canvasWidth / 2;
        float trueHPos = distanceToLineCenter * (canvasWidth / 1920);
        float x = getX() + halfWidth + (trueHPos - noteWidth / 2f) * hScale;
        float y = getY() + pos - noteHeight / 2f;
        float width = noteWidth * hScale;
        float height = noteHeight * hScale;
        return new float[]{x,y,width,height};
    }

    public Rectangle getSelectedRectangle(){
        float selectWidth = selectingX - selectingSx;
        float selectHeight = selectingY - selectingSy;
        float selectX = getX() + selectingSx;
        float selectY = getY() + selectingSy;
        if (selectWidth<0){
            selectX+=selectWidth;
            selectWidth=-selectWidth;
        }
        if (selectHeight<0){
            selectY+=selectHeight;
            selectHeight=-selectHeight;
        }
        return new Rectangle(
                selectX, selectY,
                selectWidth, selectHeight);
    }

    private void placeNote(float x,float y){
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault());
        String s = simpleDateFormat.format(new Date());
        float width = getWidth();
        float selectTime = fromWidgetYToTime(y);
        Float nearestBeatTime = TimeUtil.getNearestBeatTime(selectTime,alignmentList);
        if (nearestBeatTime==null)
            return;
        selectedTime= nearestBeatTime;
        Sample sample=new Sample();
        sample.setName("Auto sample");
        sample.setTime((long)(float)nearestBeatTime);
        sample.setName(s);
        CommonNote commonNote = getNote(x, width, sample);
        insertNoteByTime(commonNote);
    }

    private CommonNote getNote(float x, float width, Sample sample) {
        CommonNote commonNote =new CommonNote();
        CommonNote.NoteType noteType;
        switch (notePlacing){
            default:
            case 1:
                noteType= CommonNote.NoteType.Tap;
                break;
            case 2:
                noteType= CommonNote.NoteType.Drag;
                break;
            case 3:
                noteType= CommonNote.NoteType.Hold;
                break;
            case 4:
                noteType= CommonNote.NoteType.Flick;
        }
        commonNote.setNoteType(noteType);
        commonNote.setShown(true);
        commonNote.setBackGoing(false);
        commonNote.setBindLine(nowCommonLine);
        commonNote.setDistanceToLineCenter((int) ((x - width /2f)/ width *1920/hScale));
        commonNote.setBindSample(sample);
        return commonNote;
    }

    private void insertNoteByTime(CommonNote commonNote) {
        nowCommonLine.getNotes().add(commonNote);
        nowCommonLine.getNotes().sort((a, b) ->
                (int) (a.getBindSample().getTime() - b.getBindSample().getTime()));
        //((LevelLineEditorDialog) getParent()).updateNoteList();
        List<SampleSet> sampleSets = V.project.getSampleData().getSampleSets();
        int index = -1;
        String auto_sampling_set = "Automatic Sample Set";
        for (int i = 0; i < sampleSets.size(); i++) {
            if (sampleSets.get(i).getName().equals(auto_sampling_set)) {
                index = i;
                break;
            }
        }
        if (index==-1){
            SampleSet sampleSet=new SampleSet();
            sampleSet.setName(auto_sampling_set);
            sampleSets.add(sampleSet);
            index=sampleSets.size()-1;
        }
        SampleSet sampleSet = sampleSets.get(index);
        sampleSet.getSamples().add(commonNote.getBindSample());
        Collections.sort(sampleSet.getSamples(),(a,b)-> (int) (a.getTime()-b.getTime()));
    }

    private void resetNoteHitSoundStatus(){
        if (nowCommonLine ==null)return;
        ArrayList<CommonNote> commonNotes = nowCommonLine.getNotes();
        float offset = V.project.getLatosMetaData().getOffset();
        for (CommonNote commonNote : commonNotes) {
            Sample bindSample = commonNote.getBindSample();
            float absTime = bindSample.getTime();
            boolean b = nowTime-offset <= absTime;
            commonNote.getEditorExtraData()[0]=b;
        }
    }

    public void updateLine(CommonLine commonLine){
        this.nowCommonLine = commonLine;
        resetNoteHitSoundStatus();
    }

    public void updateAlignment(String alignment){
        alignmentList.clear();
        if (alignment.equals("None"))
            return;
        if (alignment.equals("Custom")){
            try{
                if (!(getParent() instanceof LevelLineEditorDialog))return;
                int i = Integer.parseInt(
                        ((LevelLineEditorDialog) getParent()).getCustomAlignmentValue());
                if (i<=0||i>=512)return;
                alignmentList.add(new Object[]{i,colorMap.get(-1)});
                alignmentList.add(new Object[]{1,colorMap.get(1)});
            }catch (Exception ignore){}
            return;
        }
        String[] strings = alignment.split("/");
        int m = Integer.parseInt(strings[1]);
        for(int i=m;i>=1;i/=2)
            alignmentList.add(new Object[]{i,colorMap.get(i)});
    }

    public void deleteNotes(){
        for (CommonNote commonNote : selectedCommonNote) {
            nowCommonLine.getNotes().remove(commonNote);
        }
    }

    public void setNotePlacing(int notePlacing) {
        this.notePlacing = notePlacing;
    }

    public void setEditDialogMode(boolean editDialogMode) {
        this.editDialogMode = editDialogMode;
    }

    public List<CommonNote> getSelectedNote() {
        return selectedCommonNote;
    }
}*/